home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / ghostscr / gsview07.zip / print.c < prev    next >
C/C++ Source or Header  |  1993-05-02  |  23KB  |  786 lines

  1. /*
  2.  * print.c --   Printing operations for GSVIEW.EXE, 
  3.  *              a graphical interface for MS-Windows Ghostscript
  4.  * Copyright (C) 1993  Russell Lang
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   Author: Russell Lang
  21.  * Internet: rjl@monu1.cc.monash.edu.au
  22.  */
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commdlg.h>
  28. #include <shellapi.h>
  29. #include <mmsystem.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <dir.h>
  35. #define NeedFunctionPrototypes 1
  36. #include "ps.h"
  37. #include "gsview.h"
  38.  
  39. /* documented in Device Driver Adaptation Guide */
  40. /* Prototypes taken from print.h */
  41. DECLARE_HANDLE(HPJOB);
  42.  
  43. HPJOB   WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
  44. int     WINAPI StartSpoolPage(HPJOB);
  45. int     WINAPI EndSpoolPage(HPJOB);
  46. int     WINAPI WriteSpool(HPJOB, LPSTR, int);
  47. int     WINAPI CloseJob(HPJOB);
  48. int     WINAPI DeleteJob(HPJOB, int);
  49. int     WINAPI WriteDialog(HPJOB, LPSTR, int);
  50. int     WINAPI DeleteSpoolPage(HPJOB);
  51.  
  52. struct prop_item_s {
  53.     char    name[MAXSTR];
  54.     char    value[MAXSTR];
  55. };
  56.  
  57. char not_defined[] = "[Not defined]";
  58.  
  59. struct prop_item_s *
  60. get_properties(char *device)
  61. {
  62. char *entries, *p;
  63. int i, numentry;
  64. struct prop_item_s *proplist;
  65.     entries = malloc(PROFILE_SIZE);
  66.     if (entries == (char *)NULL)
  67.        return NULL;
  68.     GetPrivateProfileString(device, NULL, "", entries, PROFILE_SIZE, INIFILE);
  69.     if (strlen(entries) == 0) {
  70.         free(entries);
  71.         return NULL;
  72.     }
  73.     p = entries;
  74.     for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++)
  75.         p += strlen(p) + 1;
  76.     proplist = (struct prop_item_s *)malloc((numentry+1) * sizeof(struct prop_item_s));
  77.     if (proplist == (struct prop_item_s *)NULL) {
  78.         free(entries);
  79.         return NULL;
  80.     }
  81.     p = entries;
  82.     for (i=0; i<numentry; i++) {
  83.         strcpy(proplist[i].name, p);
  84.         GetPrivateProfileString(device, p, "", proplist[i].value, sizeof(proplist->value), INIFILE);
  85.         p += strlen(p) + 1;
  86.     }
  87.     proplist[numentry].name[0] = '\0';
  88.     proplist[numentry].value[0] = '\0';
  89.     free(entries);
  90.     return proplist;
  91. }
  92.  
  93. /* dialog box for selecting printer properties */
  94. BOOL CALLBACK _export
  95. PropDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  96. {
  97.     char buf[128];
  98.     int iprop;
  99.     int ivalue;
  100.     WORD notify_message;
  101.     char *p;
  102.     char *value;
  103.     static char device[MAXSTR];    /* contains printer device name */
  104.     static struct prop_item_s* propitem;
  105.     char section[MAXSTR];
  106.  
  107.     switch (wmsg) {
  108.         case WM_INITDIALOG:
  109.         lstrcpy(device, (LPSTR)lParam);    /* initialise device name */
  110.         propitem = get_properties(device);
  111.         if (propitem == (struct prop_item_s *)NULL) {
  112.             EndDialog(hDlg, FALSE);
  113.             return TRUE;
  114.         }
  115.         for (iprop=0; propitem[iprop].name[0]; iprop++) {
  116.             SendDlgItemMessage(hDlg, PROP_NAME, CB_ADDSTRING, 0, 
  117.             (LPARAM)((LPSTR)propitem[iprop].name+1));
  118.         }
  119.         SendDlgItemMessage(hDlg, PROP_NAME, CB_SETCURSEL, 0, 0L);
  120.         /* force update of PROP_VALUE */
  121.         SendDlgNotification(hDlg, PROP_NAME, CBN_SELCHANGE);
  122.         return TRUE;
  123.         case WM_COMMAND:
  124.         notify_message = GetNotification(wParam,lParam);
  125.         switch (LOWORD(wParam)) {
  126.             case ID_HELP:
  127.                 SendMessage(hwndimg, help_message, 0, 0L);
  128.                 return(FALSE);
  129.             case PROP_NAME:
  130.             if (notify_message != CBN_SELCHANGE) {
  131.                 return FALSE;
  132.             }
  133.             iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  134.             if (iprop == CB_ERR) {
  135.                 return FALSE;
  136.             }
  137.             /* now look up entry in gsview.ini */
  138.             /* and update PROP_VALUE list box */
  139.             strcpy(section, device);
  140.             strcat(section, " values");
  141.             GetPrivateProfileString(section, propitem[iprop].name, "", buf, sizeof(buf)-2, INIFILE);
  142.             buf[strlen(buf)+1] = '\0';    /* put double NULL at end */
  143.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_RESETCONTENT, 0, 0L);
  144.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  145.                 (LPARAM)((LPSTR)not_defined));
  146.             p = buf;
  147.             if (*p != '\0') {
  148.               EnableWindow(GetDlgItem(hDlg, PROP_VALUE), TRUE);
  149.               while (*p!='\0') {
  150.                 value = p;
  151.                 while ((*p!='\0') && (*p!=','))
  152.                 p++;
  153.                 *p++ = '\0';
  154.                     SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  155.                     (LPARAM)((LPSTR)value));
  156.               }
  157.             }
  158.             SendDlgItemMessage(hDlg, PROP_VALUE, CB_SELECTSTRING, -1, (LPARAM)(LPSTR)propitem[iprop].value);
  159.                 SetDlgItemText(hDlg, PROP_VALUE, propitem[iprop].value);
  160.             return FALSE;
  161.             case PROP_VALUE:
  162.             if (notify_message == CBN_SELCHANGE) {
  163.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  164.                 if (iprop == CB_ERR)
  165.                     return FALSE;
  166.                 ivalue = (int)SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETCURSEL, 0, 0L);
  167.                 if (ivalue == CB_ERR)
  168.                     return FALSE;
  169.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETLBTEXT, ivalue, (LPARAM)(LPSTR)propitem[iprop].value);
  170.             }
  171.             if (notify_message == CBN_EDITCHANGE) {
  172.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  173.                 if (iprop == CB_ERR)
  174.                     return FALSE;
  175.                     GetDlgItemText(hDlg, PROP_VALUE, (LPSTR)propitem[iprop].value, sizeof(propitem->value));
  176.             }
  177.             return FALSE;
  178.             case IDOK:
  179.             for (iprop=0; propitem[iprop].name[0]; iprop++) {
  180.                 WritePrivateProfileString(device, propitem[iprop].name, propitem[iprop].value, INIFILE);
  181.             }
  182.             free((char *)propitem);
  183.             EndDialog(hDlg, TRUE);
  184.             return TRUE;
  185.             case IDCANCEL:
  186.             free((char *)propitem);
  187.             EndDialog(hDlg, FALSE);
  188.             return TRUE;
  189.         }
  190.         break;
  191.     }
  192.     return FALSE;
  193. }
  194.  
  195.  
  196. /* dialog box for selecting printer device and resolution */
  197. BOOL CALLBACK _export
  198. DeviceDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  199. {
  200.     char buf[128];
  201.     int idevice;
  202.     WORD notify_message;
  203.     char *p;
  204.     char *res;
  205.     int numentry;
  206.     char entry[MAXSTR];
  207.     struct prop_item_s *proplist;
  208.  
  209.     switch (wmsg) {
  210.         case WM_INITDIALOG:
  211.         p = get_devices();
  212.         res = p;    /* save for free() */
  213.         for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++) {
  214.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_ADDSTRING, 0, 
  215.             (LPARAM)((LPSTR)p));
  216.             p += strlen(p) + 1;
  217.         }
  218.         free(res);
  219.         if (SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_name)
  220.             == CB_ERR)
  221.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SETCURSEL, 0, 0L);
  222.         /* force update of DEVICE_RES */
  223.         SendDlgNotification(hDlg, DEVICE_NAME, CBN_SELCHANGE);
  224.         if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_resolution)
  225.             == CB_ERR)
  226.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  227.         return TRUE;
  228.         case WM_COMMAND:
  229.         notify_message = GetNotification(wParam,lParam);
  230.         switch (LOWORD(wParam)) {
  231.             case ID_HELP:
  232.                 SendMessage(hwndimg, help_message, 0, 0L);
  233.                 return(FALSE);
  234.             case DEVICE_NAME:
  235.             if (notify_message != CBN_SELCHANGE) {
  236.                 return FALSE;
  237.             }
  238.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  239.             if (idevice == CB_ERR) {
  240.                 return FALSE;
  241.             }
  242.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  243.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  244.                     free((char *)proplist);
  245.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), TRUE);
  246.             }
  247.             else
  248.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), FALSE);
  249.             /* now look up entry in gsview.ini */
  250.             /* and update DEVICE_RES list box */
  251.             GetPrivateProfileString(DEVSECTION, entry, "", buf, sizeof(buf)-2, INIFILE);
  252.             buf[strlen(buf)+1] = '\0';    /* double NULL at end */
  253.                 SendDlgItemMessage(hDlg, DEVICE_RES, CB_RESETCONTENT, 0, 0L);
  254.             p = buf;
  255.             if (*p == '\0') {
  256.                 /* no resolutions can be set */
  257.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RES), FALSE);
  258.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), FALSE);
  259.             }
  260.             else {
  261.               EnableWindow(GetDlgItem(hDlg, DEVICE_RES), TRUE);
  262.               EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), TRUE);
  263.               while (*p!='\0') {
  264.                 res = p;
  265.                 while ((*p!='\0') && (*p!=','))
  266.                 p++;
  267.                 *p++ = '\0';
  268.                     SendDlgItemMessage(hDlg, DEVICE_RES, CB_ADDSTRING, 0, 
  269.                     (LPARAM)((LPSTR)res));
  270.               }
  271.             }
  272.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  273.             if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)buf)
  274.                 != CB_ERR)
  275.                     SetDlgItemText(hDlg, DEVICE_RES, buf);
  276.             return FALSE;
  277.             case DEVICE_RES:
  278.             /* don't have anything to do */
  279.             return FALSE;
  280.             case DEVICE_PROP:
  281.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  282.             if (idevice == CB_ERR) {
  283.                 return FALSE;
  284.             }
  285.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  286.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  287.                     DLGPROC lpProcProp;
  288.                     free((char *)proplist);
  289.                 LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  290.                 lpProcProp = (DLGPROC)MakeProcInstance((FARPROC)PropDlgProc, phInstance);
  291.                 DialogBoxParam( phInstance, "PropDlgBox", hDlg, lpProcProp, (LPARAM)entry);
  292.                 FreeProcInstance((FARPROC)lpProcProp);
  293.             }
  294.             else
  295.                 play_sound(SOUND_ERROR);
  296.             return FALSE;
  297.             case IDOK:
  298.             /* save device name and resolution */
  299.                 GetDlgItemText(hDlg, DEVICE_NAME, device_name, sizeof(device_name));
  300.                 GetDlgItemText(hDlg, DEVICE_RES, device_resolution, sizeof(device_resolution));
  301.             EndDialog(hDlg, TRUE);
  302.             return TRUE;
  303.             case IDCANCEL:
  304.             EndDialog(hDlg, FALSE);
  305.             return TRUE;
  306.         }
  307.         break;
  308.     }
  309.     return FALSE;
  310. }
  311.  
  312.  
  313. /* Modeless dialog box - Cancel printing */
  314. BOOL CALLBACK _export
  315. CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  316. {
  317.     switch(message) {
  318.     case WM_INITDIALOG:
  319.         SetWindowText(hDlg, szAppName);
  320.         return TRUE;
  321.     case WM_COMMAND:
  322.         switch(LOWORD(wParam)) {
  323.         case IDCANCEL:
  324.             DestroyWindow(hDlg);
  325.             hDlgModeless = 0;
  326.             EndDialog(hDlg, 0);
  327.             return TRUE;
  328.         }
  329.     }
  330.     return FALSE;
  331. }
  332.  
  333. /* Dialog box to select printer port */
  334. BOOL CALLBACK _export
  335. SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  336. {
  337. LPSTR entry;
  338.     switch(message) {
  339.     case WM_INITDIALOG:
  340.         entry = (LPSTR)lParam;
  341.         while (*entry) {
  342.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM)entry);
  343.         entry += lstrlen(entry)+1;
  344.         }
  345.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM)0);
  346.         return TRUE;
  347.     case WM_COMMAND:
  348.         switch(LOWORD(wParam)) {
  349.         case SPOOL_PORT:
  350. #ifdef WIN32
  351.             if (HIWORD(wParam)
  352. #else
  353.             if (HIWORD(lParam)
  354. #endif
  355.                            == LBN_DBLCLK)
  356.             PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
  357.             return FALSE;
  358.         case IDOK:
  359.             EndDialog(hDlg, 1+(int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
  360.             return TRUE;
  361.         case IDCANCEL:
  362.             EndDialog(hDlg, 0);
  363.             return TRUE;
  364.         }
  365.     }
  366.     return FALSE;
  367. }
  368.  
  369. /* Print File to port */
  370. int
  371. gp_printfile(char *filename)
  372. {
  373. #define PRINT_BUF_SIZE 16384u
  374. char *buffer;
  375. char *portname;
  376. DLGPROC lpfnSpoolProc;
  377. int i, port;
  378. HPJOB hJob;
  379. WORD count;
  380. FILE *f;
  381. int error = FALSE;
  382. DLGPROC lpfnCancelProc;
  383. long lsize;
  384. long ldone;
  385. char fmt[MAXSTR];
  386. char pcdone[10];
  387. MSG msg;
  388.  
  389.     /* get list of ports */
  390.     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
  391.         return FALSE;
  392.     GetProfileString("ports", NULL, "", buffer, PRINT_BUF_SIZE);
  393.     /* select a port */
  394.     lpfnSpoolProc = (DLGPROC)MakeProcInstance((FARPROC)SpoolDlgProc, phInstance);
  395.     port = DialogBoxParam(phInstance, "SpoolDlgBox", hwndtext, lpfnSpoolProc, (LPARAM)buffer);
  396.     FreeProcInstance((FARPROC)lpfnSpoolProc);
  397.     if (!port) {
  398.         free(buffer);
  399.         return FALSE;
  400.     }
  401.     portname = buffer;
  402.     for (i=1; i<port && strlen(portname)!=0; i++)
  403.         portname += lstrlen(portname)+1;
  404.     
  405.     if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
  406.         free(buffer);
  407.         return FALSE;
  408.     }
  409.     fseek(f, 0L, SEEK_END);
  410.     lsize = ftell(f);
  411.     if (lsize <= 0)
  412.         lsize = 1;
  413.     fseek(f, 0L, SEEK_SET);
  414.  
  415.     hJob = OpenJob(portname, filename, (HDC)NULL);
  416.     switch ((int)hJob) {
  417.         case SP_APPABORT:
  418.         case SP_ERROR:
  419.         case SP_OUTOFDISK:
  420.         case SP_OUTOFMEMORY:
  421.         case SP_USERABORT:
  422.             fclose(f);
  423.         free(buffer);
  424.             return FALSE;
  425.     }
  426.     if (StartSpoolPage(hJob) < 0)
  427.         error = TRUE;
  428.  
  429.     lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
  430.     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", hwndimg, lpfnCancelProc);
  431.     ldone = 0;
  432.     LoadString(phInstance, IDS_CANCELDONE, fmt, sizeof(fmt));
  433.  
  434.     while (!error && hDlgModeless 
  435.       && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
  436.         if (WriteSpool(hJob, buffer, count) < 0)
  437.         error = TRUE;
  438.         ldone += count;
  439.         sprintf(pcdone, fmt, (int)(ldone * 100 / lsize));
  440.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), pcdone);
  441.         while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  442.             if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  443.             TranslateMessage(&msg);
  444.             DispatchMessage(&msg);
  445.         }
  446.         }
  447.     }
  448.     free(buffer);
  449.     fclose(f);
  450.  
  451.     if (!hDlgModeless)
  452.         error=TRUE;
  453.     DestroyWindow(hDlgModeless);
  454.     hDlgModeless = 0;
  455.     FreeProcInstance((FARPROC)lpfnCancelProc);
  456.     EndSpoolPage(hJob);
  457.     if (error)
  458.         DeleteJob(hJob, 0);
  459.     else
  460.         CloseJob(hJob);
  461.     return !error;
  462. }
  463.  
  464.  
  465. /* get a filename and spool it printing */
  466. void
  467. gsview_spool()
  468. {
  469.     static char filename[MAXSTR];
  470.  
  471.     if (!getfilename(filename, OPEN, FILTER_ALL, IDS_PRINTFILE, IDS_TOPICPRINT))
  472.         return;
  473.  
  474.     if (!gp_printfile(filename)) {
  475.         play_sound(SOUND_ERROR);
  476.         return;
  477.     }
  478. }
  479.  
  480.  
  481. char *
  482. get_devices()
  483. {
  484. HGLOBAL hglobal;
  485. LPSTR device;
  486. LPSTR lp;
  487. char *p;
  488.     p = malloc(PROFILE_SIZE);
  489.     if (p == (char *)NULL)
  490.         return (char *)NULL;
  491.  
  492.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  493.     if (strlen(p) == 0) {
  494.         /* [Devices] section doesn't exist.  Initialise from resources */
  495.         hglobal = LoadResource(phInstance, FindResource(phInstance, "gsview_devices", RT_RCDATA));
  496.         if ( (device = (LPSTR)LockResource(hglobal)) == (LPSTR)NULL)
  497.         return (char *)NULL;
  498.         while (lstrlen(device)!=0) {
  499.             for (lp = device; (*lp!='\0') && (*lp!=','); lp++)
  500.                 /* nothing */;
  501.         *lp++ = '\0';
  502.         WritePrivateProfileString(DEVSECTION, device, lp, INIFILE);
  503.         device = lp + lstrlen(lp) + 1;
  504.         }
  505.         FreeResource(hglobal);
  506.     }
  507.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  508.     return p;
  509. }
  510.  
  511. /* print a range of pages using a Ghostscript device */
  512. void
  513. gsview_print(BOOL to_file)
  514. {
  515.     int i;
  516.     BOOL flag;
  517.     DLGPROC lpProcDevice;
  518.     float print_xdpi, print_ydpi;
  519.     int width, height;
  520.  
  521.     struct prop_item_s *proplist;
  522.     
  523.     static char output[MAXSTR];    /* output filename for printing */
  524.     char *fname;            /* filename to print */
  525.     char command[256];
  526.     FILE *optfile;
  527.     int pages;
  528.     int thispage = pagenum;
  529.  
  530.     if (dfname[0] == '\0') {
  531.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  532.         return;
  533.     }
  534.     
  535.     LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  536.     lpProcDevice = (DLGPROC)MakeProcInstance((FARPROC)DeviceDlgProc, phInstance);
  537.     flag = DialogBoxParam( phInstance, "DeviceDlgBox", hwndimg, lpProcDevice, (LPARAM)NULL);
  538.     FreeProcInstance((FARPROC)lpProcDevice);
  539.     if (!flag) {
  540.         return;
  541.     }
  542.  
  543.     info_wait(TRUE);
  544.     gswin_close();    /* we need a new Ghostscript */
  545.     info_wait(FALSE);
  546.  
  547.     fname = (char *)NULL;
  548.     if (doc == (struct document *)NULL) {
  549.         play_sound(SOUND_NONUMBER);
  550.             LoadString(phInstance, IDS_PRINTINGALL, command, sizeof(command));
  551.         if (MessageBox(hwndimg, command, szAppName, MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
  552.             return;
  553.         fname = dfname;
  554.         pages = 1;
  555.     }
  556.     else {
  557.         pages = 1;
  558.         if (doc->numpages != 0) {
  559.         if (!get_page(&thispage, TRUE))
  560.             return;
  561.             pages = 0;
  562.             for (i=0; i< doc->numpages; i++) {
  563.                 if (page_list.select[i]) pages++;
  564.             }
  565.         }
  566.         if (!open_cfile())
  567.             return;
  568.         pscopydoc(cfile);
  569.         close_cfile();
  570.         fname = cfname;
  571.     }
  572.     
  573.     if (to_file) {
  574.         if (!getfilename(output, SAVE, FILTER_ALL, IDS_OUTPUTFILE, IDS_TOPICPRINT))
  575.         return;
  576.     }
  577.  
  578.     /* calculate image size */
  579.     switch (sscanf(device_resolution,"%fx%f", &print_xdpi, &print_ydpi)) {
  580.         case EOF:
  581.         case 0:
  582.             print_xdpi = print_ydpi = DEFAULT_RESOLUTION;
  583.             break;
  584.         case 1:
  585.             print_ydpi = print_xdpi;
  586.     }
  587.     i = get_papersizes_index();
  588.     if (i < 0) {
  589.         width = user_width;
  590.         width = user_height;
  591.     }
  592.     else {
  593.         width = papersizes[i].width;
  594.         height = papersizes[i].height;
  595.     }
  596.     width  = (unsigned int)(width  / 72.0 * print_xdpi);
  597.     height = (unsigned int)(height / 72.0 * print_ydpi);
  598.  
  599.  
  600.     if ((pfname[0] != '\0') && !debug)
  601.         unlink(pfname);
  602.     pfname[0] = '\0';
  603.     if ( (optfile = gp_open_scratch_file(szScratch, pfname, "w")) == (FILE *)NULL) {
  604.         play_sound(SOUND_ERROR);
  605.         return;
  606.     }
  607.     fprintf(optfile, "-dNOPAUSE\n");
  608.     fprintf(optfile, "-sDEVICE=%s\n",device_name);
  609.     fprintf(optfile, "-r%gx%g\n", (double)print_xdpi, (double)print_ydpi);
  610.     fprintf(optfile, "-g%ux%u\n",width,height);
  611.     if (to_file) {
  612.         char *p;
  613.         fprintf(optfile, "-sOutputFile=");
  614.         for (p=output; *p != '\0'; p++)
  615.             if (*p == '\\')
  616.                 fputc('/',optfile);
  617.             else
  618.                 fputc(*p,optfile);
  619.         fputc('\n',optfile);
  620.     }
  621.     if ((proplist = get_properties(device_name)) != (struct prop_item_s *)NULL) {
  622.         /* output current property selections */
  623.         for (i=0; proplist[i].name[0]; i++) {
  624.         if (strcmp(proplist[i].value, not_defined) != 0)
  625.             fprintf(optfile,"-%s=%s\n", proplist[i].name, proplist[i].value);
  626.         }
  627.         free((char *)proplist);
  628.     }
  629.     fclose(optfile);
  630.  
  631.     sprintf(command,"%s -sGSVIEW=%u @%s %s quit.ps", szGSwin,
  632.         (unsigned int)hwndimg, pfname, fname);
  633.  
  634.     if (strlen(command) > 126) {
  635.         /* command line too long */
  636.         gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR);
  637.         unlink(pfname);
  638.         pfname[0] = '\0';
  639.         gswin_hinst = (HINSTANCE)NULL;
  640.         return;
  641.     }
  642.     info_wait(TRUE);
  643.     gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE);
  644.  
  645.     if (gswin_hinst < HINSTANCE_ERROR) {
  646.         gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR);
  647.         unlink(pfname);
  648.         pfname[0] = '\0';
  649.         info_wait(FALSE);
  650.         gswin_hinst = (HINSTANCE)NULL;
  651.         return;
  652.     }
  653.  
  654.     set_timer(timeout*pages);
  655.     info_wait(TRUE);
  656.     return;
  657. }
  658.  
  659. /* extract a range of pages for later printing */
  660. void
  661. gsview_extract()
  662. {
  663.     FILE *f;
  664.     static char output[MAXSTR];
  665.     int thispage = pagenum;
  666.  
  667.     if (dfname[0] == '\0') {
  668.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  669.         return;
  670.     }
  671.  
  672.     if (doc == (struct document *)NULL) {
  673.         gserror(IDS_NOPAGE, NULL, MB_ICONEXCLAMATION, SOUND_NONUMBER);
  674.         return;
  675.     }
  676.     
  677.     if (doc->numpages != 0)
  678.         if (!get_page(&thispage, TRUE))
  679.             return;
  680.  
  681.     if (!getfilename(output, SAVE, FILTER_PS, NULL, IDS_TOPICPRINT))
  682.         return;
  683.  
  684.     if ((f = fopen(output, "wb")) == (FILE *)NULL) {
  685.         return;
  686.     }
  687.  
  688.     info_wait(TRUE);
  689.     if (doc->numpages != 0)
  690.         pscopydoc(f);
  691.     else
  692.         pscopy(dfile, f, doc->beginheader, doc->endtrailer);
  693.  
  694.     fclose(f);
  695.  
  696.     info_wait(FALSE);
  697.     return;
  698. }
  699.  
  700. /* pscopydoc is copied (with modifications) from ghostview misc.c */
  701. /* Copyright (C) 1992  Timothy O. Theisen */
  702. /* length calculates string length at compile time */
  703. /* can only be used with character constants */
  704. #define length(a) (sizeof(a)-1)
  705.  
  706. /* Copy the headers, marked pages, and trailer to fp */
  707. void
  708. pscopydoc(FILE *fp)
  709. {
  710.     char text[PSLINELENGTH];
  711.     char *comment;
  712.     BOOL pages_written = FALSE;
  713.     BOOL pages_atend = FALSE;
  714.     int pages = 0;
  715.     int page = 1;
  716.     int i;
  717.     long here;
  718.  
  719.     for (i=0; i< doc->numpages; i++) {
  720.         if (page_list.select[i]) pages++;
  721.     }
  722.  
  723.     here = doc->beginheader;
  724.     while ( (comment = pscopyuntil(dfile, fp, here,
  725.                doc->endheader, "%%Pages:")) != (char *)NULL ) {
  726.     here = ftell(dfile);
  727.     if (pages_written || pages_atend) {
  728.         free(comment);
  729.         continue;
  730.     }
  731.     sscanf(comment+length("%%Pages:"), "%s", text);
  732.     if (strcmp(text, "(atend)") == 0) {
  733.         fputs(comment, fp);
  734.         pages_atend = TRUE;
  735.     } else {
  736.         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  737.         case 1:
  738.             fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  739.             break;
  740.         default:
  741.             fprintf(fp, "%%%%Pages: %d\r\n", pages);
  742.             break;
  743.         }
  744.         pages_written = TRUE;
  745.     }
  746.     free(comment);
  747.     }
  748.     pscopy(dfile, fp, doc->beginpreview, doc->endpreview);
  749.     pscopy(dfile, fp, doc->begindefaults, doc->enddefaults);
  750.     pscopy(dfile, fp, doc->beginprolog, doc->endprolog);
  751.     pscopy(dfile, fp, doc->beginsetup, doc->endsetup);
  752.  
  753.     page = 1;
  754.     for (i = 0; i < doc->numpages; i++) {
  755.     if (page_list.select[map_page(i)])  {
  756.         comment = pscopyuntil(dfile, fp, doc->pages[i].begin,
  757.                   doc->pages[i].end, "%%Page:");
  758.         fprintf(fp, "%%%%Page: %s %d\r\n",
  759.             doc->pages[i].label, page++);
  760.         free(comment);
  761.         pscopy(dfile, fp, -1, doc->pages[i].end);
  762.     }
  763.     }
  764.  
  765.     here = doc->begintrailer;
  766.     while ( (comment = pscopyuntil(dfile, fp, here,
  767.                doc->endtrailer, "%%Pages:")) != (char *)NULL ) {
  768.     here = ftell(dfile);
  769.     if (pages_written) {
  770.         free(comment);
  771.         continue;
  772.     }
  773.     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  774.         case 1:
  775.         fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  776.         break;
  777.         default:
  778.         fprintf(fp, "%%%%Pages: %d\r\n", pages);
  779.         break;
  780.     }
  781.     pages_written = TRUE;
  782.     free(comment);
  783.     }
  784. }
  785. #undef length
  786.